class Mvue{
  constructor(options){
    this.$el = options.el;
    this.$data = options.data;
    this.$options = options;
    if(this.$el){
      //1.实现数据观察者
      new Observer(this.$data);
      //2.实现指令解析器
      new Compile(this.$el,this);
    }

  }
}
const compileUtil={
  getVal(expr,vm){
    return expr.split('.').reduce((data,currentVal)=>{
      // console.log(111,data,currentVal);
      return data[currentVal]
    },vm.$data)
  }, 
  setVal(expr,vm,newVal){
    let keyList = expr.split('.');
    console.log('aa',keyList[keyList.length-1]);
    let val = keyList.reduce((data,currentVal)=>{
      // console.log(111,data,currentVal);
      if(currentVal == keyList[keyList.length-1]){
        data[currentVal] = newVal;
      }
      return data[currentVal]
    },vm.$data)
    

  },
  getContentVal(expr,vm){
    return expr.replace(/\{\{(.+?)\}\}/g,(...args)=>{
      return this.getVal(args[1],vm)
    })
  },
  text(node,expr,vm){
    let value;
    if(expr.indexOf('{{')!==-1){
      value = expr.replace(/\{\{(.+?)\}\}/g,(...args)=>{
        console.log(args);
        new Watcher(args[1],vm,(newVal)=>{
          this.updater.textUpdater(node,this.getContentVal(expr,vm));
        })
        return this.getVal(args[1],vm)
      })
    }else{
      new Watcher(expr,vm,(newVal)=>{
        this.updater.textUpdater(node,newVal);
      })
      value = this.getVal(expr,vm);
    }
    console.log('textUpdate:',value);
    this.updater.textUpdater(node,value)
  },
  html(node,expr,vm){
    // console.log('CompileUtil');
    const value = this.getVal(expr,vm);
    new Watcher(expr,vm,(newVal)=>{
      // console.log('new Watcher');
      this.updater.htmlUpdater(node,newVal);
    })
    this.updater.htmlUpdater(node,value);
  },
  model(node,expr,vm){
    const value = this.getVal(expr,vm);

    new Watcher(expr,vm,(newVal)=>{
      this.updater.modelUpdater(node,newVal);
    })

    node.addEventListener('input',(e)=>{
      let value = e.target.value;
      this.setVal(expr,vm,value)
    })
    this.updater.modelUpdater(node,value);
  },
  on(node,expr,vm,eventName){
    let fn = vm.$options.methods && vm.$options.methods[expr]
    node.addEventListener(eventName,fn.bind(vm),false)
  },
  updater:{
    textUpdater(node,value){
      node.textContent = value;
    },
    htmlUpdater(node,value){
      // console.log(222,node,value);
      node.innerHTML = value;
    },
    modelUpdater(node,value){
      node.value = value
    }
  }
}
class Compile{
  constructor(el,vm){
    this.el  = this.isElementNode(el)?el:document.querySelector(el)
    this.vm = vm;
    //1.获取文档碎片对象 放入内存中，会减少页面的回流和重绘
    const fragment =this.node2Fragment(this.el);
    //2.编译模板
    this.compile(fragment)
    //3.追加子元素到更元素
    this.el.appendChild(fragment);
  }
  isElementNode(node){
    return node.nodeType ===1;
  }
  node2Fragment(el){
    //创建文档碎片
    const f = document.createDocumentFragment();
    let firstChild;
    while(firstChild =el.firstChild){
      f.append(firstChild);

    }
    return f
    
  }
  compile(fragment){
    //1.获取每个子节点
    const childNodes = fragment.childNodes;
    [...childNodes].forEach(child=>{
      // console.log(child);
      if(this.isElementNode(child)){
        //是元素节点
        //编译元素节点
        // console.log('元素节点：',child);
        this.compileElement(child);
      }else{
        //文本节点
        //编译文本节点
        // console.log('文本节点：',child);
        this.compileText(child);
      }
      if(child.childNodes&&child.childNodes.length){
        this.compile(child)
      }
    })
  }
  compileElement(node){
    const attributes = node.attributes;
    // console.log(attributes);
    Array.from(attributes).forEach(attr=>{
      // console.log(attr);
      const {name,value} = attr;
      if(this.isDirective(name)){//是一个指令
        const [,directive] =name.split('-')
        const [dirName,eventName]=directive.split(':');
        //更新数据视图
        compileUtil[dirName](node,value,this.vm,eventName)
        //删除有指令的标签上的属性
        node.removeAttribute('v-'+directive);
      }else if(this.isEventName(name)){
        const [,eventName]=name.split('@');
        compileUtil['on'](node,value,this.vm,eventName) 
      }
    })
  }
  compileText(node){
    const content = node.textContent;
    if(/\{\{(.+?)\}\}/.test(content)){
      // console.log(content);
      compileUtil['text'](node,content,this.vm)
    }
  }
  isDirective(attrName){
    return attrName.startsWith('v-')
  }
  isEventName(attrName){
    return attrName.startsWith('@')
  }
}